package configs

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/viper"
	"gopkg.in/yaml.v3"
)

type Config struct {
	Server    ServerConfig    `yaml:"server" mapstructure:"server"`
	Database  DatabaseConfig  `yaml:"database" mapstructure:"database"`
	Generator GeneratorConfig `yaml:"generator" mapstructure:"generator"`
	Logging   LoggingConfig   `yaml:"logging" mapstructure:"logging"`
}

type ServerConfig struct {
	Host         string `yaml:"host" mapstructure:"host"`
	Port         int    `yaml:"port" mapstructure:"port"`
	Mode         string `yaml:"mode" mapstructure:"mode"`
	ReadTimeout  int    `yaml:"read_timeout" mapstructure:"read_timeout"`
	WriteTimeout int    `yaml:"write_timeout" mapstructure:"write_timeout"`
}

type DatabaseConfig struct {
	URI            string `yaml:"uri" mapstructure:"uri"`
	Name           string `yaml:"name" mapstructure:"name"`
	ConnectTimeout int    `yaml:"connect_timeout" mapstructure:"connect_timeout"`
	QueryTimeout   int    `yaml:"query_timeout" mapstructure:"query_timeout"`
	MaxPoolSize    int    `yaml:"max_pool_size" mapstructure:"max_pool_size"`
}

type GeneratorConfig struct {
	DefaultBatchSize int    `yaml:"default_batch_size" mapstructure:"default_batch_size"`
	MaxBatchSize     int    `yaml:"max_batch_size" mapstructure:"max_batch_size"`
	WorkerCount      int    `yaml:"worker_count" mapstructure:"worker_count"`
	OutputDir        string `yaml:"output_dir" mapstructure:"output_dir"`
	TemplateDir      string `yaml:"template_dir" mapstructure:"template_dir"`
}

type LoggingConfig struct {
	Level  string `yaml:"level" mapstructure:"level"`
	Format string `yaml:"format" mapstructure:"format"`
	Output string `yaml:"output" mapstructure:"output"`
}

// 默认配置
func DefaultConfig() *Config {
	return &Config{
		Server: ServerConfig{
			Host:         "localhost",
			Port:         8080,
			Mode:         "debug",
			ReadTimeout:  30,
			WriteTimeout: 30,
		},
		Database: DatabaseConfig{
			URI:            "mongodb://localhost:27017",
			Name:           "mongen",
			ConnectTimeout: 10,
			QueryTimeout:   30,
			MaxPoolSize:    100,
		},
		Generator: GeneratorConfig{
			DefaultBatchSize: 1000,
			MaxBatchSize:     10000,
			WorkerCount:      4,
			OutputDir:        "./output",
			TemplateDir:      "./templates",
		},
		Logging: LoggingConfig{
			Level:  "info",
			Format: "text",
			Output: "stdout",
		},
	}
}

// 配置加载器
type ConfigLoader struct {
	config *Config
}

func NewConfigLoader() *ConfigLoader {
	return &ConfigLoader{
		config: DefaultConfig(),
	}
}

// 从文件加载配置
func (cl *ConfigLoader) LoadFromFile(configPath string) error {
	viper.SetConfigFile(configPath)
	viper.SetConfigType("yaml")

	if err := viper.ReadInConfig(); err != nil {
		return fmt.Errorf("读取配置文件失败: %w", err)
	}

	if err := viper.Unmarshal(cl.config); err != nil {
		return fmt.Errorf("解析配置文件失败: %w", err)
	}

	return nil
}

// 从环境变量加载配置
func (cl *ConfigLoader) LoadFromEnv() {
	// 设置环境变量前缀
	viper.SetEnvPrefix("MONGEN")
	viper.AutomaticEnv()

	// 替换分隔符
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// 绑定环境变量
	envMappings := map[string]string{
		"server.host":                  "SERVER_HOST",
		"server.port":                  "SERVER_PORT",
		"server.mode":                  "SERVER_MODE",
		"database.uri":                 "DATABASE_URI",
		"database.name":                "DATABASE_NAME",
		"database.connect_timeout":     "DATABASE_CONNECT_TIMEOUT",
		"generator.default_batch_size": "GENERATOR_DEFAULT_BATCH_SIZE",
		"generator.max_batch_size":     "GENERATOR_MAX_BATCH_SIZE",
		"generator.worker_count":       "GENERATOR_WORKER_COUNT",
		"generator.output_dir":         "GENERATOR_OUTPUT_DIR",
		"generator.template_dir":       "GENERATOR_TEMPLATE_DIR",
		"logging.level":                "LOGGING_LEVEL",
		"logging.format":               "LOGGING_FORMAT",
	}

	for viperKey, envKey := range envMappings {
		viper.BindEnv(viperKey, envKey)
	}

	// 将环境变量值更新到配置
	viper.Unmarshal(cl.config)
}

// 应用CLI选项覆盖配置
func (cl *ConfigLoader) ApplyCliOptions(opts *CliOptions) {
	if opts.MongoURI != "" {
		cl.config.Database.URI = opts.MongoURI
	}
	if opts.DatabaseName != "" {
		cl.config.Database.Name = opts.DatabaseName
	}
	if opts.BatchSize > 0 {
		cl.config.Generator.DefaultBatchSize = opts.BatchSize
	}
	if opts.OutputDir != "" {
		cl.config.Generator.OutputDir = opts.OutputDir
	}
	if opts.TemplateDir != "" {
		cl.config.Generator.TemplateDir = opts.TemplateDir
	}
	if opts.LogLevel != "" {
		cl.config.Logging.Level = opts.LogLevel
	}
}

// CLI选项结构
type CliOptions struct {
	ConfigFile   string
	MongoURI     string
	DatabaseName string
	BatchSize    int
	OutputDir    string
	TemplateDir  string
	LogLevel     string
}

// 获取最终配置
func (cl *ConfigLoader) GetConfig() *Config {
	return cl.config
}

// 保存配置到文件
func (cl *ConfigLoader) SaveToFile(configPath string) error {
	// 确保目录存在
	if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
		return fmt.Errorf("创建配置目录失败: %w", err)
	}

	data, err := yaml.Marshal(cl.config)
	if err != nil {
		return fmt.Errorf("序列化配置失败: %w", err)
	}

	if err := os.WriteFile(configPath, data, 0644); err != nil {
		return fmt.Errorf("写入配置文件失败: %w", err)
	}

	return nil
}

// 验证配置
func (cl *ConfigLoader) Validate() error {
	cfg := cl.config

	// 验证服务器配置
	if cfg.Server.Port < 1 || cfg.Server.Port > 65535 {
		return fmt.Errorf("无效的服务器端口: %d", cfg.Server.Port)
	}

	// 验证数据库配置
	if cfg.Database.URI == "" {
		return fmt.Errorf("数据库URI不能为空")
	}

	// 验证生成器配置
	if cfg.Generator.DefaultBatchSize <= 0 {
		return fmt.Errorf("默认批量大小必须大于0")
	}

	if cfg.Generator.MaxBatchSize < cfg.Generator.DefaultBatchSize {
		return fmt.Errorf("最大批量大小不能小于默认批量大小")
	}

	return nil
}

// 全局配置加载函数
func Load(opts *CliOptions) (*Config, error) {
	loader := NewConfigLoader()

	// 1. 加载环境变量
	loader.LoadFromEnv()

	// 2. 加载配置文件（如果指定）
	if opts.ConfigFile != "" {
		if err := loader.LoadFromFile(opts.ConfigFile); err != nil {
			return nil, err
		}
	}

	// 3. 应用CLI选项覆盖
	loader.ApplyCliOptions(opts)

	// 4. 验证配置
	if err := loader.Validate(); err != nil {
		return nil, err
	}

	return loader.GetConfig(), nil
}

// 便捷方法
func (c *Config) GetMongoURI() string {
	return c.Database.URI
}

func (c *Config) GetDatabaseName() string {
	return c.Database.Name
}

func (c *Config) GetServerAddress() string {
	return fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port)
}

func (c *Config) GetOutputDir() string {
	return c.Generator.OutputDir
}

func (c *Config) GetTemplateDir() string {
	return c.Generator.TemplateDir
}
